package com.changge.common.limit.strategy;

import com.changge.common.core.utils.StringUtil;
import com.changge.common.limit.LimitManager;
import com.changge.common.limit.annotation.AccessLimit;
import com.changge.common.limit.exception.LimitErrorCode;
import com.changge.common.redis.service.IRedisService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.script.RedisScript;

import java.util.Collections;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * Redis限流策略
 *
 * @author zhangrongkang
 * @since 2024/2/14
 */
@Slf4j
public class RedisLimit implements LimitManager {

    @Autowired
    private RedisScript<Long> redisScript;

    @Autowired
    private IRedisService redisService;

    /**
     * 请求限流
     *
     * @param accessLimit 自定义限流注解
     * @return 是否请求成功
     */
    @Override
    public boolean tryAccess(AccessLimit accessLimit) {
        // 获取注解参数信息
        String key = accessLimit.key();
        // 校验Key是否合法
        if (StringUtil.isBlank(key)) {
            throw LimitErrorCode.INTERFACE_KEY_NOT_NULL.exception();
        }
        long timeout = accessLimit.timeout();
        int max = accessLimit.max();
        TimeUnit timeunit = accessLimit.timeunit();
        // 将限流时间转为秒数作为Redis中key的过期时间
        long expire = timeunit.toSeconds(timeout);
        // 执行Lua脚本
        Long count = redisService.execute(redisScript, Collections.singletonList(key), Integer.toString(max), expire);
        // 根据返回内容判断是否限流成功
        return Objects.nonNull(count) && count != 0;
    }
}
